001    /*
002     * Copyright 2004 Niclas Hedhman
003     *
004     * Licensed  under the  Apache License,  Version 2.0  (the "License");
005     * you may not use  this file  except in  compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed  under the  License is distributed on an "AS IS" BASIS,
012     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    package net.dpml.util;
019    
020    import java.util.Enumeration;
021    import java.util.Properties;
022    import java.util.Stack;
023    import java.util.StringTokenizer;
024    
025    import net.dpml.transit.Transit;
026    
027    /**
028     * Utility class that handles substitution of property names in the string
029     * for ${value} relative to a supplied set of properties.
030     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
031     * @version 1.0.1
032     */
033    public final class PropertyResolver
034    {
035        // ------------------------------------------------------------------------
036        // static
037        // ------------------------------------------------------------------------
038    
039        static
040        {
041            Object xx = Transit.DPML_DATA;
042        }
043    
044       /**
045        * System property symbol substitution from properties.
046        * Replace any occurances of ${[key]} with the value of the property
047        * assigned to the [key] in the system properties.
048        * @param value a string containing possibly multiple ${[value]} sequences
049        * @return the expanded string
050        */
051        public static String resolve( String value )
052        {
053            Properties properties = System.getProperties();
054            return resolve( properties, value );
055        }
056        
057       /**
058        * System property symbol substitution from properties.
059        * Replace any occurances of ${[key]} with the value of the property
060        * assigned to the [key] in the system properties or supplied properties.
061        * @param properties an arbitary properties file containing unresolved properties
062        * @return the property file with expended properties
063        */
064        public static Properties resolve( Properties properties )
065        {
066            Properties system = System.getProperties();
067            Enumeration names = properties.propertyNames();
068            while( names.hasMoreElements() )
069            {
070                String name = (String) names.nextElement();
071                String old = properties.getProperty( name );
072                String value = resolve( old );
073                String v2 = resolve( properties, value );
074                if( !v2.equals( old ) )
075                {
076                    properties.setProperty( name, v2 );
077                }
078            }
079            return properties;
080        }
081        
082       /**
083        * Symbol substitution from properties.
084        * Replace any occurances of ${[key]} with the value of the property
085        * assigned to the [key] in the supplied properties argument.
086        * @param props the source properties from which substitution is resolved
087        * @param value a string containing possibly multiple ${[value]} sequences
088        * @return the expanded string
089        */
090        public static String resolve( Properties props, String value )
091        {
092            if( value == null )
093            {
094                return null;
095            }
096    
097            // optimization for common case.
098            if( value.indexOf( '$' ) < 0 )
099            {
100                return value;
101            }
102            int pos1 = value.indexOf( "${" );
103            if( pos1 < 0 )
104            {
105                return value;
106            }
107    
108            Stack stack = new Stack();
109            StringTokenizer st = new StringTokenizer( value, "${}", true );
110    
111            while ( st.hasMoreTokens() )
112            {
113                String token = st.nextToken();
114    
115                if( token.equals( "}" ) )
116                {
117                    String name = (String) stack.pop();
118                    String open = (String) stack.pop();
119                    if( open.equals( "${" ) )
120                    {
121                        String propValue = System.getProperty( name );
122                        if( propValue == null )
123                        {
124                            propValue = props.getProperty( name );
125                        }
126                        if( propValue == null )
127                        {
128                            push( stack, "${" + name + "}" );
129                        }
130                        else
131                        {
132                            push( stack, propValue );
133                        }
134                    }
135                    else
136                    {
137                        push( stack, "${" + name + "}" );
138                    }
139                }
140                else
141                {
142                    if( token.equals( "$" ) )
143                    {
144                        stack.push( "$" );
145                    }
146                    else
147                    {
148                        push( stack, token );
149                    }
150                }
151            }
152            String result = "";
153            while ( stack.size() > 0 )
154            {
155                result = stack.pop() + result;
156            }
157            return result;
158        }
159    
160       /**
161        * Pushes a value on a stack
162        * @param stack the stack
163        * @param value the value
164        */
165        private static void push( Stack stack , String value )
166        {
167            if( stack.size() > 0 )
168            {
169                String data = (String) stack.pop();
170                if( data.equals( "${" ) )
171                {
172                    stack.push( data );
173                    stack.push( value );
174                }
175                else
176                {
177                    stack.push( data + value );
178                }
179            }
180            else
181            {
182                stack.push( value );
183            }
184        }
185    
186        // ------------------------------------------------------------------------
187        // constructor
188        // ------------------------------------------------------------------------
189    
190       /**
191        * Null constructor.
192        */
193        private PropertyResolver()
194        {
195        }
196    }
197